﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Graphics;
using System.IO;
using MMOEng.Managers;
using MMOEng.SubSystems;
using MMOEng.World;
using System.ComponentModel;

namespace MMOEng
{
    public class MMOGame : Game
    {
        //TEMP
        public LevelBrick lb;
        public Grid grid;
        public Matrix GlobalView;
        public Matrix GlobalProjection;


        //Managers
        private Dictionary<string, BaseManager> registeredManagers;
        /// <summary>
        /// Register a manager with the game engine. Registering a manager provides automatic content loading as well as
        /// updating and drawing on every game tick
        /// </summary>
        /// <param name="name">Name of class for this manager. NOTE: THIS MUST BE THE CLASS NAME AS IT IS DEFINED 
        /// IN THE CLASS'S C# SOURCE FILE!!!!!</param>
        /// <param name="manager">Reference to the manager which shall be registered</param>
        public void RegisterManager(string name, BaseManager manager)
        {
            if (registeredManagers.ContainsKey(name))
            {
                registeredManagers[name] = manager;
                return;
            }
            registeredManagers.Add(name, manager);
        }
        /// <summary>
        /// All network related tasks used by the engine
        /// </summary>
        public NetworkManager NetworkManager { 
            get { return (NetworkManager)(registeredManagers["NetworkManager"]); } 
            private set { registeredManagers["NetworkManager"] = value; }
        }
        public SubSystemsManager SubSystemsManager {
            get { return (SubSystemsManager)(registeredManagers["SubSystemsManager"]); }
            private set { registeredManagers["SubSystemsManager"] = value; }
        }
        public ResourceManager ResourceManager {
            get { return (ResourceManager)(registeredManagers["ResourceManager"]); }
            private set { registeredManagers["ResourceManager"] = value; }
        }

        //Base class managers
        public GraphicsDeviceManager GraphicsDeviceManager { get; private set; }

        //System forwarders
        public RenderSubSystem RenderSystem { get { return SubSystemsManager.RenderSystem; } } 

        //Aux classes
        private GameConfiguration GameConfiguration { get; set; }
        public SpriteBatch SpriteManager { get; private set; }

        private float y;
        public MMOGame(string title) : base()
        {
            //init managers
            registeredManagers = new Dictionary<string, BaseManager>();
            GraphicsDeviceManager = new GraphicsDeviceManager(this);
            SubSystemsManager = new SubSystemsManager(this);
            ResourceManager = new ResourceManager(this);
            NetworkManager = null;

            //Game Configuration
            if(File.Exists("game.conf")){
                GameConfiguration = GameConfiguration.Load("game.conf");
            } else {
                GameConfiguration = GameConfiguration.Defaults();
            }

            this.Content.RootDirectory = "Content\\";

            //window title
            Window.Title = title;

            //Test for now
            ConnectToServer("127.0.0.1", 2010);


            //TEMP
            y = 0;
        }

        protected override void OnExiting(object sender, EventArgs args)
        {
            base.OnExiting(sender, args);

            GameConfiguration.Save("game.conf");
        }

        public void ConnectToServer(string address, ushort port)
        {
            //Connect to a server
            NetworkManager = new NetworkManager(this, address,port);
            //Load network manager content
            NetworkManager.LoadContent();
        }

        protected override void Update(GameTime gameTime)
        {
            //Update managers the run every frame
            foreach (BaseManager man in registeredManagers.Values)
            {
                man.Update(gameTime);
            }

            //TEMp
            y += 0.5f;
            GlobalView = Matrix.CreateLookAt(new Vector3(-20, 50, 20), new Vector3(100, 0, -100), Vector3.UnitY);
            float aspectRatio = (float)GraphicsDevice.Viewport.Width /
                (float)GraphicsDevice.Viewport.Height;
            float fov = MathHelper.PiOver4 * aspectRatio * 3 / 4;
            GlobalProjection = Matrix.CreatePerspectiveFieldOfView(fov,
                aspectRatio, .1f, 100000f);

            lb.Update(gameTime);
            lb.View = GlobalView;
            lb.Projection = GlobalProjection;
            lb.World = Matrix.Identity;// CreateTranslation(new Vector3(0, 0, 0));
            grid.ProjectionMatrix = GlobalProjection;
            grid.ViewMatrix = GlobalView;
            grid.WorldMatrix = Matrix.Identity;// CreateTranslation(new Vector3(0, 0, 0));

            base.Update(gameTime);
        }

        protected override void LoadContent()
        {
            //set game config
            GameConfiguration.SetGraphiccsSettings(this);

            //Load up sprite manager
            SpriteManager = new SpriteBatch(GraphicsDeviceManager.GraphicsDevice);

            //Only load if we have connected
            //if(NetworkManager != null)
            //    NetworkManager.LoadContent();

            //Load all subsystems
            foreach (BaseManager man in registeredManagers.Values)
            {
                man.LoadContent();
            }

            //TEMP
            lb = new LevelBrick(this, "Textures/World/Heightmaps/h_02");
            lb.LoadContent();
            lb.SetGridCoordinates(0, 0);
            grid = new Grid();
            grid.LoadGraphicsContent(this.GraphicsDevice);
            grid.GridScale = 1.0f;
            grid.GridSize = 32;

            base.LoadContent();
        }

        protected override void UnloadContent()
        {
            base.UnloadContent();
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            //Draw subsystems
            foreach (BaseManager man in registeredManagers.Values)
            {
                man.Draw(gameTime);
            }

            //TEMP
            lb.Draw(gameTime);
            grid.Draw();

            SpriteManager.Begin();
            SpriteManager.DrawString(ResourceManager.GetResource<SpriteFont>("Fonts/defaultFont"), "Y loc: " + y, new Vector2(0, 14), Color.Turquoise);
            SpriteManager.End();

            base.Draw(gameTime);
        }
    }
}
